package cn.ztydata.teachingsystem.heaven.service;

import cn.ztydata.teachingsystem.common.Page;
import cn.ztydata.teachingsystem.exception.ServiceException;
import cn.ztydata.teachingsystem.heaven.common.WebContext;
import cn.ztydata.teachingsystem.heaven.cons.Constants;
import cn.ztydata.teachingsystem.heaven.cons.Roles;
import cn.ztydata.teachingsystem.heaven.dao.*;
import cn.ztydata.teachingsystem.heaven.entity.Clazz;
import cn.ztydata.teachingsystem.heaven.entity.Role;
import cn.ztydata.teachingsystem.heaven.entity.Teacher;
import cn.ztydata.teachingsystem.heaven.exception.ExcelException;
import cn.ztydata.teachingsystem.util.ExcelUtil;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.util.*;

/**
 * 班级服务类
 * Created by fanruiping on 2015/5/5.
 */
@Service
public class ClassService extends BaseService{
    @Autowired
    private ClassDao classDao;//班级dao
    @Autowired
    private TeacherDao teacherDao;//教师dao
    @Autowired
    private DepartmentDao departmentDao;//系部dao
    @Autowired
    private SpecialtyDao specialtyDao;//专业dao
    @Autowired
    private StudentDao studentDao;//学生Dao
    @Autowired
    private RoleDao roleDao;//教师角色

    @Autowired
    private WebContext webContext;
    /**
     * 读取Excel文件
     * @param in 文件输入流
     * @return List
     *
     * @author fanruiping
     * @since 2015-05-05
     */
    public List<Clazz> readFromExcel(InputStream in) {
        //定义标题-属性的映射
        LinkedHashMap<String, String> fieldMap = Maps.newLinkedHashMap();
        fieldMap.put("班级名称", "name");
        fieldMap.put("班级代码", "number");
        fieldMap.put("系部代码", "deptNum");
        fieldMap.put("专业代码", "specNum");
        fieldMap.put("班主任代码", "teacherNum");

        return ExcelUtil.excelToList(in, Clazz.class, fieldMap);
    }


    /**
     * 检查导入班级数据集合中的班级代码
     * @param classList 教师集合
     *
     * @author fanruiping
     * @since 2014-12-04
     */
    public void checkForNum(final List<Clazz> classList) {
        if (classList.size() > Constants.TOTAL_2K) {
            log.debug("导入的班级数量条数超过2000");

            throw new ExcelException("导入数据量超过" + Constants.TOTAL_2K);
        }

        //获取班级代码集合
        Set<String> classNums = Sets.newHashSet();
        int index = 1;

        log.debug("循环班级列表，获取班级代码");
        //循环班级列表，获取班级代码
        for (Clazz clazz : classList) {
            //判断班级代码是否为null
            if (clazz.getNumber() == null) {
                log.debug("班级代码为null:clazz.getNumber() == null");

                throw new ExcelException("导入数据中第" + (index + 1) + "条数据的班级代码为空");
            }

            //检查导入数据中是否存在重复代码
            if (classNums.contains(clazz.getNumber())) {
                log.debug("班级代码已存在:classNums.contains(clazz.getNumber())");

                throw new ExcelException("导入数据中第" + (index + 1) + "条数据的代码重复" );
            }

            classNums.add(clazz.getNumber());
            index++;
        }

        //检查导入班级代码是否与班级主表中的数据重复
        String duplicateNum = classDao.getDuplicateNum(classNums);

        if(null == duplicateNum || duplicateNum.isEmpty()){
            log.debug("班级主表中不含指定班级代码:null == duplicateNum || duplicateNum.isEmpty()");

            //检查导入班级代码是否与归档表中的数据重复
            duplicateNum = classDao.getDuplicateNumInHistory(classNums);
        }

        classNums.clear();

        if (duplicateNum != null) {
            log.debug("导入数据中的班级代码未与数据表中重复");

            throw new ExcelException("班级代码为:" + duplicateNum + "的班级信息已经存在");
        }
    }

    /**
     * 批量新增教师
     * @param clazzList 班级信息集合
     *
     * @author fanruiping
     * @since 2015-05-05
     */
    @Transactional
    public void saveClasses(final List<Clazz> clazzList) {
        try {
            //执行批量插入
            classDao.saveClasses(clazzList);
        } catch (DataAccessException ex) {
            log.warn("批量导入班级信息异常", ex);

            throw new ExcelException();
        }
    }

    /**
     * 归档班级数据
     *
     * @author fanruiping
     * @since 2015-05-05
     */
    @Transactional
    public void setClassHistory(){
        classDao.saveHistory();
        classDao.deleteAll();
    }

    /**
     * 获取班级列表数据
     * @param departNum 系部编码
     * @param specNum 专业编码
     * @param tag 标记
     * @param page 页码
     * @param pageSize 每页显示条数
     * @return Page
     *
     * @author fanruiping
     * @since 2015-05-05
     */
    public Page<Clazz> getList(String departNum,String specNum,int tag,int page,int pageSize){
        //存储当前用户可查看的系部编码集合
        List<String> deptNums = new ArrayList<>();
        if(!departNum.isEmpty()){
            deptNums.add(departNum);
        }

        //存储当前用户可查看的专业编码集合
        List<String> specNums = new ArrayList<>();
        if(!specNum.isEmpty()){
            specNums.add(specNum);
        }

        //判断当前用户是系部管理员且未限制系部编码
        if(Roles.DEPT_ADMIN == webContext.getRole() && departNum.isEmpty()){
            //获取所负责系部编码集合
            Set<Long> deptIds = roleDao.getByTeacherId(webContext.getUserId(),2);

            if(!deptIds.isEmpty()){
                deptNums = departmentDao.getNumberByIds(deptIds);
            }
        }else if(Roles.SPEC_LEADER == webContext.getRole() && specNum.isEmpty()){
            //获取所负责专业编码集合
            specNums = specialtyDao.getNumberByLeader(webContext.getUserId());
        }

        Page<Clazz> clazzPage = classDao.getList(deptNums,specNums,tag,page,pageSize);

        //判断数据是否为空
        if(clazzPage.getItems().isEmpty()){
            log.debug("未获取到班级列表数据:clazzPage.getItems().isEmpty()");

            return clazzPage;
        }

        //存储教师工号集合
        List<String> teacherNums = new ArrayList<>();

        log.debug("循环获取教师工号、系部代码和专业代码:Clazz clazz : clazzPage.getItems()");
        //循环获取教师工号、系部代码、专业代码
        for(Clazz clazz : clazzPage.getItems()){
            teacherNums.add(clazz.getTeacherNum());

            //判断系部代码集合为空
            if(deptNums.isEmpty()){
                deptNums.add(clazz.getDeptNum());
            }

            //判断专业代码集合为空
            if(specNums.isEmpty()){
                specNums.add(clazz.getSpecNum());
            }
        }

        Map<String,String> teachers = teacherDao.getNameByNums(teacherNums);
        Map<String,String> departs = departmentDao.getNamesByNumbers(deptNums);
        Map<String,String> specs = specialtyDao.getNamesByNumbers(specNums);

        log.debug("循环插入教师名称、系部名称和专业名称:Clazz clazz : clazzPage.getItems()");
        //循环插入教师名称、系部名称、专业名称
        for(Clazz clazz : clazzPage.getItems()){
            clazz.setTeacherName(teachers.get(clazz.getTeacherNum()));
            clazz.setDeptName(departs.get(clazz.getDeptNum()));
            clazz.setSpecName(specs.get(clazz.getSpecNum()));
        }

        return clazzPage;
    }

    /**
     * 删除指定班级信息
     * @param id 班级编号
     * @return boolean
     *
     * @author fanruiping
     * @since 2015-05-05
     */
    public void deleteById(Long id){
        //获取班级明细
        Clazz clazz = classDao.getById(id);

        //判断班级是否存在
        if(null == clazz){
            log.debug("指定班级数据不存在:null == clazz");

            throw new ServiceException("指定删除的班级数据不存在");
        }

        //判断班级下是否含有学生
        if(studentDao.checkClassHasStudent(clazz.getNumber())){
            log.debug("指定班级下有学生，不能删除:studentDao.checkClassHasStudent(clazz.getNumber())");

            throw new ServiceException("指定删除的班级下含有学生，不能删除");
        }

        //判断删除班级数据失败
        if(!classDao.deleteById(id)){
            log.debug("删除班级数据失败:!classDao.deleteById(id)");

            throw new ServiceException("删除指定班级数据失败");
        }
    }
}
